package skin.support.utils;

/**
 * author : huyi
 * date   : 2023/2/6
 * desc   :
 */
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public final class AsyncThreadUtils {
    private static final Handler HANDLER = new Handler(Looper.getMainLooper());
    private static final Map<Integer, Map<Integer, ExecutorService>> TYPE_PRIORITY_POOLS = new HashMap();
    private static final Map<AsyncThreadUtils.Task, ExecutorService> TASK_POOL_MAP = new ConcurrentHashMap();
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final byte TYPE_IO = -4;
    private static Executor sDeliver;

    public AsyncThreadUtils() {
    }

    public static void runOnUiThread(Runnable runnable) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            runnable.run();
        } else {
            HANDLER.post(runnable);
        }

    }

    public static ExecutorService getIoPool() {
        return getPoolByTypeAndPriority();
    }

    public static ExecutorService getIoPool(int priority) {
        return getPoolByTypeAndPriority(priority);
    }

    public static <T> void executeByIo(AsyncThreadUtils.Task<T> task) {
        execute(getPoolByTypeAndPriority(), task);
    }

    public static void cancel(AsyncThreadUtils.Task task) {
        if (task != null) {
            task.cancel();
        }
    }

    public static void cancel(AsyncThreadUtils.Task... tasks) {
        if (tasks != null && tasks.length != 0) {
            AsyncThreadUtils.Task[] var1 = tasks;
            int var2 = tasks.length;

            for(int var3 = 0; var3 < var2; ++var3) {
                AsyncThreadUtils.Task task = var1[var3];
                if (task != null) {
                    task.cancel();
                }
            }

        }
    }

    public static void cancel(List<AsyncThreadUtils.Task> tasks) {
        if (tasks != null && tasks.size() != 0) {
            Iterator var1 = tasks.iterator();

            while(var1.hasNext()) {
                AsyncThreadUtils.Task task = (AsyncThreadUtils.Task)var1.next();
                if (task != null) {
                    task.cancel();
                }
            }

        }
    }

    public static void cancel(ExecutorService executorService) {
        if (executorService instanceof AsyncThreadUtils.ThreadPoolExecutor4Util) {
            Iterator var1 = TASK_POOL_MAP.entrySet().iterator();

            while(var1.hasNext()) {
                Entry<AsyncThreadUtils.Task, ExecutorService> taskTaskInfoEntry = (Entry)var1.next();
                if (taskTaskInfoEntry.getValue() == executorService) {
                    cancel((AsyncThreadUtils.Task)taskTaskInfoEntry.getKey());
                }
            }
        } else {
            Log.e("ThreadUtils", "The executorService is not ThreadUtils's pool.");
        }

    }

    public static void setDeliver(Executor deliver) {
        sDeliver = deliver;
    }

    private static <T> void execute(ExecutorService pool, AsyncThreadUtils.Task<T> task) {
        execute(pool, task, (TimeUnit)null);
    }

    private static <T> void execute(ExecutorService pool, AsyncThreadUtils.Task<T> task, TimeUnit unit) {
        synchronized(TASK_POOL_MAP) {
            if (TASK_POOL_MAP.get(task) != null) {
                Log.e("ThreadUtils", "Task can only be executed once.");
                return;
            }

            TASK_POOL_MAP.put(task, pool);
        }

        pool.execute(task);
    }

    private static ExecutorService getPoolByTypeAndPriority() {
        return getPoolByTypeAndPriority(5);
    }

    private static ExecutorService getPoolByTypeAndPriority(int priority) {
        synchronized(TYPE_PRIORITY_POOLS) {
            Map<Integer, ExecutorService> priorityPools = (Map)TYPE_PRIORITY_POOLS.get(-4);
            ExecutorService pool;
            if (priorityPools == null) {
                priorityPools = new ConcurrentHashMap();
                pool = AsyncThreadUtils.ThreadPoolExecutor4Util.createPool(priority);
                priorityPools.put(priority, pool);
                TYPE_PRIORITY_POOLS.put(-4, priorityPools);
            } else {
                pool = (ExecutorService)priorityPools.get(priority);
                if (pool == null) {
                    pool = AsyncThreadUtils.ThreadPoolExecutor4Util.createPool(priority);
                    priorityPools.put(priority, pool);
                }
            }

            return pool;
        }
    }

    private static Executor getGlobalDeliver() {
        if (sDeliver == null) {
            sDeliver = new Executor() {
                public void execute(Runnable command) {
                    AsyncThreadUtils.runOnUiThread(command);
                }
            };
        }

        return sDeliver;
    }

    public abstract static class Task<T> implements Runnable {
        private static final int NEW = 0;
        private static final int RUNNING = 1;
        private static final int EXCEPTIONAL = 2;
        private static final int COMPLETING = 3;
        private static final int CANCELLED = 4;
        private static final int INTERRUPTED = 5;
        private static final int TIMEOUT = 6;
        private final AtomicInteger state = new AtomicInteger(0);
        private volatile boolean isSchedule;
        private volatile Thread runner;
        private Timer mTimer;
        private long mTimeoutMillis;
        private AsyncThreadUtils.Task.OnTimeoutListener mTimeoutListener;
        private Executor deliver;

        public Task() {
        }

        public abstract T doInBackground() throws Throwable;

        public abstract void onSuccess(T var1);

        public abstract void onCancel();

        public abstract void onFail(Throwable var1);

        public void run() {
            if (this.isSchedule) {
                if (this.runner == null) {
                    if (!this.state.compareAndSet(0, 1)) {
                        return;
                    }

                    this.runner = Thread.currentThread();
                    if (this.mTimeoutListener != null) {
                        Log.w("ThreadUtils", "Scheduled task doesn't support timeout.");
                    }
                } else if (this.state.get() != 1) {
                    return;
                }
            } else {
                if (!this.state.compareAndSet(0, 1)) {
                    return;
                }

                this.runner = Thread.currentThread();
                if (this.mTimeoutListener != null) {
                    this.mTimer = new Timer();
                    this.mTimer.schedule(new TimerTask() {
                        public void run() {
                            if (!Task.this.isDone() && Task.this.mTimeoutListener != null) {
                                Task.this.timeout();
                                Task.this.mTimeoutListener.onTimeout();
                            }

                        }
                    }, this.mTimeoutMillis);
                }
            }

            try {
                final T result = this.doInBackground();
                if (this.isSchedule) {
                    if (this.state.get() != 1) {
                        return;
                    }

                    this.getDeliver().execute(new Runnable() {
                        public void run() {
                            Task.this.onSuccess(result);
                        }
                    });
                } else {
                    if (!this.state.compareAndSet(1, 3)) {
                        return;
                    }

                    this.getDeliver().execute(new Runnable() {
                        public void run() {
                            Task.this.onSuccess(result);
                            Task.this.onDone();
                        }
                    });
                }
            } catch (InterruptedException var2) {
                this.state.compareAndSet(4, 5);
            } catch (final Throwable var3) {
                if (!this.state.compareAndSet(1, 2)) {
                    return;
                }

                this.getDeliver().execute(new Runnable() {
                    public void run() {
                        Task.this.onFail(var3);
                        Task.this.onDone();
                    }
                });
            }

        }

        public void cancel() {
            this.cancel(true);
        }

        public void cancel(boolean mayInterruptIfRunning) {
            synchronized(this.state) {
                if (this.state.get() > 1) {
                    return;
                }

                this.state.set(4);
            }

            if (mayInterruptIfRunning && this.runner != null) {
                this.runner.interrupt();
            }

            this.getDeliver().execute(new Runnable() {
                public void run() {
                    Task.this.onCancel();
                    Task.this.onDone();
                }
            });
        }

        private void timeout() {
            synchronized(this.state) {
                if (this.state.get() > 1) {
                    return;
                }

                this.state.set(6);
            }

            if (this.runner != null) {
                this.runner.interrupt();
            }

            this.onDone();
        }

        public boolean isCanceled() {
            return this.state.get() >= 4;
        }

        public boolean isDone() {
            return this.state.get() > 1;
        }

        public AsyncThreadUtils.Task<T> setDeliver(Executor deliver) {
            this.deliver = deliver;
            return this;
        }

        public AsyncThreadUtils.Task<T> setTimeout(long timeoutMillis, AsyncThreadUtils.Task.OnTimeoutListener listener) {
            this.mTimeoutMillis = timeoutMillis;
            this.mTimeoutListener = listener;
            return this;
        }

        private void setSchedule(boolean isSchedule) {
            this.isSchedule = isSchedule;
        }

        private Executor getDeliver() {
            return this.deliver == null ? AsyncThreadUtils.getGlobalDeliver() : this.deliver;
        }

        protected void onDone() {
            AsyncThreadUtils.TASK_POOL_MAP.remove(this);
            if (this.mTimer != null) {
                this.mTimer.cancel();
                this.mTimer = null;
                this.mTimeoutListener = null;
            }

        }

        public interface OnTimeoutListener {
            void onTimeout();
        }
    }

    public abstract static class SimpleTask<T> extends AsyncThreadUtils.Task<T> {
        public SimpleTask() {
        }

        public void onCancel() {
            Log.e("ThreadUtils", "onCancel: " + Thread.currentThread());
        }

        public void onFail(Throwable t) {
            Log.e("ThreadUtils", "onFail: ", t);
        }
    }

    static final class UtilsThreadFactory extends AtomicLong implements ThreadFactory {
        private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
        private static final long serialVersionUID = -9209200509960368598L;
        private final String namePrefix;
        private final int priority;
        private final boolean isDaemon;

        UtilsThreadFactory(String prefix, int priority) {
            this(prefix, priority, false);
        }

        UtilsThreadFactory(String prefix, int priority, boolean isDaemon) {
            this.namePrefix = prefix + "-pool-" + POOL_NUMBER.getAndIncrement() + "-thread-";
            this.priority = priority;
            this.isDaemon = isDaemon;
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, this.namePrefix + this.getAndIncrement()) {
                public void run() {
                    try {
                        super.run();
                    } catch (Throwable var2) {
                        Log.e("ThreadUtils", "Request threw uncaught throwable", var2);
                    }

                }
            };
            t.setDaemon(this.isDaemon);
            t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
                public void uncaughtException(Thread t, Throwable e) {
                    System.out.println(e);
                }
            });
            t.setPriority(this.priority);
            return t;
        }
    }

    private static final class LinkedBlockingQueue4Util extends LinkedBlockingQueue<Runnable> {
        private volatile AsyncThreadUtils.ThreadPoolExecutor4Util mPool;
        private int mCapacity = 2147483647;

        LinkedBlockingQueue4Util() {
        }

        LinkedBlockingQueue4Util(boolean isAddSubThreadFirstThenAddQueue) {
            if (isAddSubThreadFirstThenAddQueue) {
                this.mCapacity = 0;
            }

        }

        LinkedBlockingQueue4Util(int capacity) {
            this.mCapacity = capacity;
        }

        public boolean offer(Runnable runnable) {
            return this.mCapacity <= this.size() && this.mPool != null && this.mPool.getPoolSize() < this.mPool.getMaximumPoolSize() ? false : super.offer(runnable);
        }
    }

    static final class ThreadPoolExecutor4Util extends ThreadPoolExecutor {
        private final AtomicInteger mSubmittedCount = new AtomicInteger();
        private AsyncThreadUtils.LinkedBlockingQueue4Util mWorkQueue;

        private static ExecutorService createPool(int priority) {
            return new AsyncThreadUtils.ThreadPoolExecutor4Util(2 * AsyncThreadUtils.CPU_COUNT + 1, 2 * AsyncThreadUtils.CPU_COUNT + 1, 30L, TimeUnit.SECONDS, new AsyncThreadUtils.LinkedBlockingQueue4Util(), new AsyncThreadUtils.UtilsThreadFactory("io", priority));
        }

        ThreadPoolExecutor4Util(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, AsyncThreadUtils.LinkedBlockingQueue4Util workQueue, ThreadFactory threadFactory) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
            workQueue.mPool = this;
            this.mWorkQueue = workQueue;
        }

        private int getSubmittedCount() {
            return this.mSubmittedCount.get();
        }

        protected void afterExecute(Runnable r, Throwable t) {
            this.mSubmittedCount.decrementAndGet();
            super.afterExecute(r, t);
        }

        public void execute(Runnable command) {
            if (!this.isShutdown()) {
                this.mSubmittedCount.incrementAndGet();

                try {
                    super.execute(command);
                } catch (RejectedExecutionException var3) {
                    Log.e("ThreadUtils", "This will not happen!");
                    this.mWorkQueue.offer(command);
                } catch (Throwable var4) {
                    this.mSubmittedCount.decrementAndGet();
                }

            }
        }
    }
}
